Skip to content

fix: ResponsiveContainer -1 error & projects sort order#242

Merged
SurviveM merged 11 commits intoawsl-project:mainfrom
ymkiux:main
Feb 22, 2026
Merged

fix: ResponsiveContainer -1 error & projects sort order#242
SurviveM merged 11 commits intoawsl-project:mainfrom
ymkiux:main

Conversation

@ymkiux
Copy link
Contributor

@ymkiux ymkiux commented Feb 22, 2026

Summary

  • Fix Recharts ResponsiveContainer reporting width(-1) height(-1) by using fixed pixel height instead of percentage
  • Add minHeight guard to ChartContainer's ResponsiveContainer
  • Sort projects list by createdAt to ensure consistent display order on refresh
  • Upgrade bytedance/sonic v1.14.2 → v1.15.0 for Go 1.26.0 compatibility
  • Add keepPreviousData to usage stats query

Closes #204
Closes #220

🤖 Generated with Claude Code

Summary by CodeRabbit

发布说明

  • 新功能

    • 项目列表现在按创建时间排序
  • Bug 修复

    • 改进了图表容器的响应式布局,确保正确填充可用空间
    • 改进了数据加载体验,在加载新数据时显示之前的数据
    • 优化了统计页面的图表尺寸设置
  • 样式

    • 代码格式化调整

ymkiux and others added 11 commits February 11, 2026 22:48
- Use fixed pixel height instead of percentage for ResponsiveContainer
- Add minHeight guard to ChartContainer's ResponsiveContainer
- Upgrade bytedance/sonic v1.14.2 → v1.15.0 for Go 1.26.0 compat
- Add keepPreviousData to usage stats query

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Closes awsl-project#204

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Feb 22, 2026

📝 Walkthrough

总体概览

本次更改通过以下方式修复了两个问题:为项目列表添加按创建时间的排序逻辑,优化图表容器的尺寸配置(添加显式宽高和最小高度),改进数据查询的缓存表现,以及微调 UI 组件布局。

变更内容

队列 / 文件 变更摘要
项目排序功能
web/src/pages/projects/index.tsx
新增 useMemo 钩子,实现按 createdAt 升序排列项目的逻辑,以 id 作为次级排序条件。更新了项目存在性判断和列表渲染逻辑以依赖排序后的数据。
图表容器尺寸修复
web/src/components/ui/chart.tsx, web/src/pages/stats/index.tsx
为 ChartContainer 的子元素添加 ResponsiveContainer 包装,配置显式的宽度、高度和最小高度。将统计页面的图表容器高度从动态 100% 调整为固定的 400px,防止在项目切换时的尺寸异常。
查询缓存优化
web/src/hooks/queries/use-usage-stats.ts
导入 keepPreviousData 并将其应用于 useUsageStats 查询配置,在加载新数据期间保持显示前次数据。
代码格式化
web/src/components/layout/app-sidebar/nav-user.tsx
添加文件末尾换行符,无功能影响。

预计代码审查工作量

🎯 3 (中等) | ⏱️ ~20 分钟

相关 PR

建议审查人

  • awsl233777
  • liril-net
  • Bowl42

庆祝诗

🐰 项目排序齐整齐,图表尺寸不再迷,
缓存数据平滑过,切换项目零报错!
细微微调显威力,bug 消灭乐无限。✨

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 20.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed PR标题清晰准确地总结了主要变更:修复ResponsiveContainer -1错误和项目排序问题。
Linked Issues check ✅ Passed 代码变更完全满足关联问题的需求:通过ResponsiveContainer的固定高度和minHeight解决#220的图表宽高错误,通过sortedProjects实现#204的创建日期排序。
Out of Scope Changes check ✅ Passed 所有代码变更均与关联问题直接相关,包括图表容器调整、项目排序、查询数据保留等,无超出范围的修改。

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Tip

Issue Planner is now in beta. Read the docs and try it out! Share your feedback on Discord.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@SurviveM SurviveM merged commit c28434c into awsl-project:main Feb 22, 2026
1 of 2 checks passed
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
web/src/pages/stats/index.tsx (3)

1022-1022: 多余的 JSX 空白字符字面量

</ComposedChart>{' '} 中的 {' '} 是无意义的空格字面量,建议删除。

🧹 建议修复
-                      </ComposedChart>{' '}
+                      </ComposedChart>
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/stats/index.tsx` at line 1022, Remove the meaningless
whitespace literal after the ComposedChart closing tag: locate the closing JSX
tag </ComposedChart> in the stats page component and delete the trailing {' '}
token so the JSX no longer contains the redundant space literal; no other logic
changes are needed (keep the rest of the surrounding JSX as-is).

729-739: 统计页的项目筛选列表未同步排序

projects/index.tsx 已按 createdAt 升序排序(修复 issue #204),但此处的项目筛选 chips 仍直接遍历原始 projects(API 返回顺序),导致两处展示顺序不一致。

♻️ 建议在筛选列表中应用相同排序
-{projects && projects.length > 0 && (
+{projects && projects.length > 0 && (() => {
+  const sorted = projects.slice().sort((a, b) => {
+    const tA = new Date(a.createdAt).getTime() || 0;
+    const tB = new Date(b.createdAt).getTime() || 0;
+    return tA !== tB ? tA - tB : a.id - b.id;
+  });
+  return (
   <FilterSection
     label={t('stats.project')}
     showClear={projectId !== 'all'}
     onClear={() => setProjectId('all')}
   >
-    {projects.map((p) => (
+    {sorted.map((p) => (
       <FilterChip
         key={p.id}
         selected={projectId === String(p.id)}
         onClick={() => setProjectId(String(p.id))}
       >
         {p.name}
       </FilterChip>
     ))}
   </FilterSection>
-)}
+  );
+})()}

或者将排序逻辑提取为与 projects/index.tsx 共享的 hook/util。

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/stats/index.tsx` around lines 729 - 739, The project filter
chips are rendered from the unsorted projects array (projects.map) causing order
mismatch with projects/index.tsx which sorts by createdAt; update the rendering
in the stats page to use the same sort (e.g., sort projects by createdAt
ascending before mapping to FilterChip, or move the sorting into a shared
utility/hook used by both pages) so FilterChip, projectId and setProjectId usage
remains identical but the list order matches projects/index.tsx.

481-481: keepPreviousData 下切换筛选条件无加载反馈

启用 keepPreviousData 后,切换筛选条件时 isLoading 保持 false(占位数据存在),图表会静默显示旧数据直到新数据到达,用户无法感知正在刷新。

♻️ 建议利用 `isFetching` 展示轻量加载状态
-const { data: stats, isLoading } = useUsageStats(filter);
+const { data: stats, isLoading, isFetching, isPlaceholderData } = useUsageStats(filter);

然后在图表卡片上叠加半透明遮罩或微型 spinner:

-<Card className="border-border/50 bg-card/50 backdrop-blur-sm">
+<Card className={cn('border-border/50 bg-card/50 backdrop-blur-sm', isFetching && 'opacity-60 pointer-events-none')}>

Also applies to: 882-885

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/stats/index.tsx` at line 481, The current use of
useUsageStats(filter) with keepPreviousData causes isLoading to stay false
during filter switches, so add useUsageStats's isFetching (e.g., const { data:
stats, isLoading, isFetching } = useUsageStats(filter)) and use isFetching to
drive a lightweight loading UI; update the chart/card components that render
stats to show a semi-transparent overlay or small spinner when isFetching is
true (while still rendering previous stats) so users see a refresh indicator —
adjust the chart container(s) where stats is used to conditionally render the
overlay based on isFetching.
web/src/pages/projects/index.tsx (1)

48-59: 排序比较器中每项 Date 对象重复实例化

new Date(a.createdAt)Number.isFinite(...) 检查和 .getTime() 取值时各创建一次,可合并为一次。

♻️ 建议优化
 return projects.slice().sort((a, b) => {
-  const timeA = Number.isFinite(new Date(a.createdAt).getTime())
-    ? new Date(a.createdAt).getTime()
-    : 0;
-  const timeB = Number.isFinite(new Date(b.createdAt).getTime())
-    ? new Date(b.createdAt).getTime()
-    : 0;
+  const rawA = new Date(a.createdAt).getTime();
+  const rawB = new Date(b.createdAt).getTime();
+  const timeA = Number.isFinite(rawA) ? rawA : 0;
+  const timeB = Number.isFinite(rawB) ? rawB : 0;
   if (timeA !== timeB) {
     return timeA - timeB;
   }
   return a.id - b.id;
 });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@web/src/pages/projects/index.tsx` around lines 48 - 59, The sort comparator
repeatedly constructs Date objects for each side (new Date(a.createdAt) and new
Date(b.createdAt)) twice; to fix, create and reuse a single Date instance per
item inside the comparator (e.g., const dateA = new Date(a.createdAt) and const
dateB = new Date(b.createdAt)), compute their getTime() once, validate with
Number.isFinite and fall back to 0, then compare those cached times and finally
a.id - b.id; update the comparator in the projects.slice().sort(...) callback to
use these local dateA/dateB and timeA/timeB variables.
📜 Review details

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2589cea and 105d809.

📒 Files selected for processing (5)
  • web/src/components/layout/app-sidebar/nav-user.tsx
  • web/src/components/ui/chart.tsx
  • web/src/hooks/queries/use-usage-stats.ts
  • web/src/pages/projects/index.tsx
  • web/src/pages/stats/index.tsx
🔇 Additional comments (4)
web/src/hooks/queries/use-usage-stats.ts (1)

120-120: keepPreviousData 用法正确,符合 TanStack Query v5 规范

v5 中将此功能从 keepPreviousData: true(v4 选项)迁移至 placeholderData: keepPreviousData,使用方式完全正确。

web/src/components/ui/chart.tsx (1)

66-68: 修复正确,minHeight={1} 有效防止 -1 错误

ChartContainer 的包裹 div 上有硬编码的 aspect-video 类(aspect-ratio: 16/9),可为 height="100%" 提供可测量的父容器高度。同时,children 的 TypeScript 类型(ResponsiveContainer['children'])从类型层面防止了误传另一个 ResponsiveContainer 导致的嵌套问题。

web/src/pages/stats/index.tsx (1)

901-902: 固定像素高度修复正确

height={400}(数值型)让 ResponsiveContainer 直接使用 400px 固定高度而非测量父容器百分比,从根本上规避了 -1 错误。外层 div 的 h-[400px] 保证布局空间,min-h-[400px] 防止容器坍缩,三者配合合理。

web/src/pages/projects/index.tsx (1)

44-60: 排序实现逻辑正确

slice() 避免原数组变异,createdAt 升序 + id 稳定兜底,Number.isFinite 正确处理无效日期,[projects] 依赖项设置准确。

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@web/src/pages/projects/index.tsx`:
- Around line 48-59: The sort comparator repeatedly constructs Date objects for
each side (new Date(a.createdAt) and new Date(b.createdAt)) twice; to fix,
create and reuse a single Date instance per item inside the comparator (e.g.,
const dateA = new Date(a.createdAt) and const dateB = new Date(b.createdAt)),
compute their getTime() once, validate with Number.isFinite and fall back to 0,
then compare those cached times and finally a.id - b.id; update the comparator
in the projects.slice().sort(...) callback to use these local dateA/dateB and
timeA/timeB variables.

In `@web/src/pages/stats/index.tsx`:
- Line 1022: Remove the meaningless whitespace literal after the ComposedChart
closing tag: locate the closing JSX tag </ComposedChart> in the stats page
component and delete the trailing {' '} token so the JSX no longer contains the
redundant space literal; no other logic changes are needed (keep the rest of the
surrounding JSX as-is).
- Around line 729-739: The project filter chips are rendered from the unsorted
projects array (projects.map) causing order mismatch with projects/index.tsx
which sorts by createdAt; update the rendering in the stats page to use the same
sort (e.g., sort projects by createdAt ascending before mapping to FilterChip,
or move the sorting into a shared utility/hook used by both pages) so
FilterChip, projectId and setProjectId usage remains identical but the list
order matches projects/index.tsx.
- Line 481: The current use of useUsageStats(filter) with keepPreviousData
causes isLoading to stay false during filter switches, so add useUsageStats's
isFetching (e.g., const { data: stats, isLoading, isFetching } =
useUsageStats(filter)) and use isFetching to drive a lightweight loading UI;
update the chart/card components that render stats to show a semi-transparent
overlay or small spinner when isFetching is true (while still rendering previous
stats) so users see a refresh indicator — adjust the chart container(s) where
stats is used to conditionally render the overlay based on isFetching.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

统计模块切换项目时图表渲染报宽高尺寸异常错误 项目添加顺序和显示顺序不一致

2 participants